﻿// Copyright © Transeric Solutions 2011.  All rights reserved.
// Licensed under Code Project Open License (see http://www.codeproject.com/info/cpol10.aspx).
// Author: Eric David Lynch.
using System;

namespace Camstar.Utils.csv
{
    /// <summary>
    /// Properties that are common to both CSV readers and writers.
    /// </summary>
    public abstract class CsvBase : IDisposable
    {
        #region Constructors

        /// <summary>
        /// Initialize a new instance of the CsvBase class.
        /// </summary>
        protected CsvBase()
        {
            // Set the default values for auto-implemented properties
            CommentChar = '#';
            EndColumnChar = ',';
            EndRowChar = '\n';
            EscapeChar = '\\';

            // Update options to reflect default
            UpdateOptions();
        }

        #endregion // Constructors

        #region Protected data

        /// <summary>
        /// Allow both double and single quotes to enclose a column value (to escape reserved characters).
        /// </summary>
        protected bool isAllQuote;

        /// <summary>
        /// A value indicating if comments are allowed.
        /// </summary>
        protected bool isComment;

        /// <summary>
        /// A value indicating if comment characters are allowed after the first character.
        /// </summary>
        protected bool isCommentInLine;

        /// <summary>
        /// A value indicating if comment characters can be quoted / escaped.
        /// </summary>
        protected bool isCommentQuote;

        /// <summary>
        /// Use two consecutive quoting characters to escape quotes within a column value.
        /// </summary>
        protected bool isDouble;

        /// <summary>
        /// Recognize empty lines.
        /// </summary>
        protected bool isEmptyLine;

        /// <summary>
        /// Allow the escape character within quoted column values.
        /// </summary>
        protected bool isEscape;

        /// <summary>
        /// Allow the escape character outside of quoted column values.
        /// </summary>
        protected bool isFreeEscape;

        /// <summary>
        /// A value indicating if we are positioned within a row.
        /// </summary>
        protected bool isInRow;

        /// <summary>
        /// Allow double quotes to enclose a column value (to escape reserved characters).
        /// </summary>
        protected bool isQuote;

        /// <summary>
        /// Allow single quotes to enclose a column value (to escape reserved characters).
        /// </summary>
        protected bool isSingleQuote;

        /// <summary>
        /// The behavioral options for this reader.
        /// </summary>
        protected CsvOption options = CsvOption.Default;

        #endregion // Protected data

        #region Events

        /// <summary>
        /// Occurs when the end of a row is read or written.
        /// </summary>
        public event EventHandler RowEnd;

        #endregion // Events

        #region Properties

        /// <summary>
        /// Gets a value indicating if a cancellation is pending.
        /// </summary>
        public bool CancellationPending { get; protected set; }

        /// <summary>
        /// Gets or sets the character used to introduce comments.
        /// </summary>
        /// <remarks>
        /// This property is ignored unless CsvOption.Comment is specified.
        /// </remarks>
        public char CommentChar { get; set; }

        /// <summary>
        /// Gets or sets the character that indicates the end of a column.
        /// </summary>
        public char EndColumnChar { get; set; }

        /// <summary>
        /// Gets or sets the character that indicates the end of a row.
        /// </summary>
        public char EndRowChar { get; set; }

        /// <summary>
        /// Gets or sets the escape character used to include special characters.
        /// </summary>
        /// <remarks>
        /// This is dependent on the Escape and FreeEscape options.
        /// </remarks>
        public char EscapeChar { get; set; }

        /// <summary>
        /// Gets or sets the behavioral options.
        /// </summary>
        public CsvOption Options
        {
            get { return options; }
            set
            {
                options = value;
                UpdateOptions();
            }
        }

        #endregion // Properties

        #region Public methods

        /// <summary>
        /// Asynchronously cancel long-running operations.
        /// </summary>
        public void CancelAsync()
        {
            CancellationPending = true;
        }

        #endregion // Public methods

        #region Protected methods

        /// <summary>
        /// Raise the RowEnd event.
        /// </summary>
        /// <param name="e">The event arguments.</param>
        protected virtual void OnRowEnd(
            EventArgs e)
        {
            // If we have subscribers, notify them
            if (RowEnd != null)
                RowEnd(this, e);
        }

        /// <summary>
        /// Update option variables based on value of options.
        /// </summary>
        protected virtual void UpdateOptions()
        {
            isSingleQuote = (options & CsvOption.SingleQuote) != 0;
            isFreeEscape = (options & CsvOption.FreeEscape) != 0;
            isDouble = (options & CsvOption.Double) != 0;
            isEscape = (options & CsvOption.Escape) != 0;
            isQuote = (options & CsvOption.Quote) != 0;
            isComment = (options & CsvOption.Comment) != 0;
            isCommentInLine = isComment && (options & CsvOption.CommentLine) == 0;
            isCommentQuote = isComment && (options & CsvOption.CommentQuote) != 0;
            isEmptyLine = (options & CsvOption.EmptyLine) != 0;
            isAllQuote = isQuote || isSingleQuote;
        }

        #endregion // Protected methods

        #region IDisposable Members

        /// <summary>
        /// Dispose of resources associated with this instance.
        /// </summary>
        public abstract void Dispose();

        #endregion
    }
}